#pragma once 
#include<list>
#include<mutex>
#include"room.hpp"
#include<condition_variable>
template<class T> 
class match_queue
{
    private:
        //使用链表二不使用queue的原因是:有中间删除元素的需求
        std::list<T> _list;
        //实现线程安全
        std::mutex _mutex;
        //条件变量主要是为了阻塞消费者,当队列中元素个数<2时阻塞
        std::condition_variable _cond;
    public:
        int size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _list.size();
        }
        //判空
        bool empty()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _list.empty();
        }
        //阻塞线程
        void wait()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _cond.wait(lock);
        }
        //入队列,并唤醒线程
        void push(const T& data)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _list.push_back(data);
            _cond.notify_all();
            return ;
        }
        //出队列
        bool pop(T& data)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_list.empty())
            {
                return false; 
            }
            data = _list.front();
            return true;
        }
        //移除指定的数据
        void remove(T& data)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _list.remove(data);
            return;
        }
};
class match_manage
{
    private:
        //三个等级的匹配队列
        match_queue<uint64_t> _q_bronze;
        match_queue<uint64_t> _q_silver;
        match_queue<uint64_t> _q_gold;
        //三个等级的匹配线程 
        std::thread _th_bronze;
        std::thread _th_silver;
        std::thread _th_gold;
        room_manage* _rm;
        user_table* _ut;
        online_manager* _om;
    private:
        void handle_match(match_queue<uint64_t>& mq)
        {
            while(1)
            {
                //1. 判断队列人数是否大于2,<2 则阻塞等待
                while(mq.size() < 2)
                {
                    mq.wait();
                }
                //2. 至此,代表队列中人数够了,出队两个玩家
                uint64_t uid1,uid2;
                bool ret = mq.pop(uid1);
                if(ret == false)
                {
                    continue;
                }
                ret = mq.pop(uid2);
                if(ret == false)
                {
                    this->add(uid1);//当第二次pop失败时,将第一次pop数据再次放入匹配队列中
                    continue;
                }
                //3. 校验两个玩家是否在线,如果有人掉线,则要把另一人重新添加入队列
                websocketsvr::connection_ptr conn1 = _om->get_conn_from_hall(uid1);
                if(conn1.get() == nullptr)
                {
                    this->add(uid2);
                    continue;
                }
                websocketsvr::connection_ptr conn2 = _om->get_conn_from_hall(uid2);
                if(conn2.get() == nullptr)
                {
                    this->add(uid1);
                    continue;
                }
                //4. 为两个玩家创建房间,并将玩家加入房间中
                room_ptr rp = _rm->cteate_room(uid1,uid2);
                if(rp.get() == nullptr)
                {
                    this->add(uid1);
                    this->add(uid2);
                    continue;
                }
                //5. 对两个玩家进行响应
                Json::Value resp;
                resp["optype"] = "match_success";
                resp["result"] = true;
                std::string body;
                json_util::serialize(resp,body);
                conn1->send(body);
                conn2->send(body);
            }
        }
    public:
        void th_bronze_entry()
        {
            return handle_match(_q_bronze);
        }
        void th_silver_entry()
        {
            return handle_match(_q_silver);
        }
        void th_gold_entry()
        {
            return handle_match(_q_gold);
        }
        match_manage(room_manage*rm, user_table* ut,online_manager* om)
        :_rm(rm),_ut(ut),_om(om)
        ,_th_bronze(std::thread(&match_manage::th_bronze_entry,this))
        ,_th_silver(std::thread(&match_manage::th_silver_entry,this))
        ,_th_gold(std::thread(&match_manage::th_gold_entry,this))
        {
            LOG(DEBUG,"游戏匹配模块初始化完毕...\n");
        }
        ~match_manage()
        {

        }
        bool add(uint64_t uid)
        {
            //根据玩家的天梯分数,来判定玩家的档次,添加到不同的匹配队列
            //1. 根据玩家ID,获取玩家信息
            Json::Value user;
            bool ret  = _ut->select_by_id(uid,user);
            if(ret == false)
            {
                LOG(DEBUG,"获取玩家信息:%d 信息失败!!\n",uid);
                return false;
            }
            //获取玩家信息中的得分
            int score = user["score"].asInt();
            //2. 添加到指定的队列中
            if(score < 2000)
            {
                _q_bronze.push(uid);
            }
            else if(score >= 2000 && score < 3000)
            {
                _q_silver.push(uid);
            }
            else
            {
                _q_gold.push(uid);
            }
            return true;
        }
        bool del(uint64_t uid)
        {
            Json::Value user;
            bool ret = _ut->select_by_id(uid,user);
            if(ret == false)
            {
                LOG(DEBUG,"获取玩家:%d 信息失败!!!\n");
                return false;
            }
            //获取玩家信息中的得分
            int score = user["score"].asInt();
            //2. 添加到指定的队列中
            if(score < 2000)
            {
                _q_bronze.remove(uid);
            }
            else if(score >= 2000 && score < 3000)
            {
                _q_gold.remove(uid);
            }
            else
            {
                _q_gold.remove(uid);
            }
            return true;
        }
};